<html lang="zh-CN">
<head>
  <meta charset="utf-8">
  <title>文档</title>
  
  <link href="../css/semantic/semantic.min.css" rel="stylesheet">
  <link href="../css/markdown.css" rel="stylesheet">
  <link href="../css/wtxynavigation.css" rel="stylesheet">
  <script src="../js/jquery.min.js"></script>
  <script type="text/javascript" src="../js/include.js"></script>
  <style>
    body{padding-top:0;background:#f7f7f7}
    body>.ui.container{width:100%;padding:0}
    #project-title{background:#6e6e6e;width:100%;line-height:3.572rem;color:#fff;font-size:1.2rem}
    #project-title .title-wrap{font-weight:700;padding:0 12px;width:100%;max-width:1366px!important;min-width:900px;margin:0 auto}
    #project-title .left,#project-title right{display:inline-block}
    #project-title .right{float:right}
    #project-title .right .wiki-actions .menu{left:auto;right:0;margin-top:.4em!important}
    #wiki-preview-container{width:100%;max-width:1366px!important;min-width:900px;padding:0;border:1px solid #e3e9ed;border-top:0}
    #wiki-preview>.ui.segment{margin-top:0;padding:1rem;padding-left:0;border:0}
    .hover-places{display:inline-block}
    #page-detail{width:60%;margin:0 auto}
    #page-detail .title{font-weight:700;font-size:24px;padding:12px 0;border-bottom:1px solid #ccc}
    #page-detail .content{margin-top:15px}
    .content p{word-wrap:break-word}
    #wiki-parent,#wiki-title,#wikis{display:none}
    .ui.grid{padding:0!important}
    #ex-all{cursor:pointer;color:#537c8d}
  </style>
</head>
<body>
  <div class="ui container">
    <div id="project-title">
      <div class="title-wrap">
        <div class="left">
          <i class="icon eye"></i>
          文档预览:
          mianmSDK
        </div>
        <div class="right">
          Export by Gitee
        </div>
      </div>
    </div>

    <div class="ui container" id="wiki-preview-container">
      <div id="wiki-preview">
        <div class="ui segment">
          <div id="page-detail" class="markdown-body">
            <div class='title'>32.runloop的数据结构</div><div class='content'><h1>
<a id="runloop的数据结构" class="anchor" href="#runloop%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84"></a>runloop的数据结构</h1>
<p><strong>关键词</strong>: <code>runloop</code>, <code>CFRunLoopRef</code>,<code>CFRunLoopMode</code>,<code>Source</code>,<code>Timer</code>,<code>Observer</code>,<code>RunLoopCommonModes</code>,<code>mode</code></p>
<ul>
<li>
<code>OC</code>里面提供了两个<code>runloop</code>, <code>NSRunLoop</code>和<code>CFRunLoopRef</code>.</li>
<li>
<code>NSRunLoop</code>是对<code>CFRunLoopRef</code>的封装, 提供了面向对象的<code>API</code>.</li>
<li>苹果<code>CF</code>开头的是开源的, 然后下面是通过<code>CFRunLoopRef</code>来讲解的</li>
</ul>
<p>runloop的主要数据结构有如下:</p>
<ol>
<li><strong>CFRunLoopRef</strong></li>
<li><strong>CFRunLoopMode</strong></li>
<li><strong>Source/Timer/Observer</strong></li>
</ol>
<h2>
<a id="1-cfrunloopref" class="anchor" href="#1-cfrunloopref"></a>1. CFRunLoopRef</h2>
<ol>
<li>
<p><strong>pthread</strong>: <strong>C语言线</strong>程对象</p>
<ul>
<li>
<code>Runloop</code> 和线程的关系是, <strong>一一对应</strong>
</li>
<li>
</li>
</ul>
</li>
<li>
<p><strong>currentMode</strong>: <code>Runloop</code>当前所处的模式</p>
<ul>
<li>是<code>CFRunLoopMode</code> 数据结构</li>
<li>
</li>
</ul>
</li>
<li>
<p><strong>modes</strong>: 是多个<code>mode</code>的集合</p>
<ul>
<li>是集合结构, 里面装的是上面那个<strong>CFRunLoopMode</strong>, <code>NSMutableSet &lt;CFRunLoopMode *&gt;;</code>
</li>
</ul>
</li>
<li>
<p><strong>commonModes</strong></p>
<ul>
<li>是集合, 里面装的<strong>字符串</strong><code>NSMutableSet &lt;NSString *&gt;;</code>
</li>
</ul>
</li>
<li>
<p><strong>commonModeItems</strong></p>
<ul>
<li>
<code>commonModeItems</code>, 它是一个集合, 集合里面有多个元素, 有多个<strong>Observer</strong> ,有多个<strong>Timer</strong> ,有多个<strong>Source</strong>
</li>
</ul>
</li>
</ol>
<p><img src="images/runloopdata01.png" alt="runloopdata01"></p>
<h2>
<a id="2-cfrunloopmode" class="anchor" href="#2-cfrunloopmode"></a>2. CFRunLoopMode</h2>
<p>包含如下:</p>
<ol>
<li>
<code>name</code>: 对应的就是某一个<code>mode</code>的名称
<ul>
<li>经常使用的比如<code>NSDefaultRunLoopMode</code>
</li>
</ul>
</li>
<li>
<code>sources0</code>: 集合类型的数据结构<code>MutableSet</code>
</li>
<li>
<code>sources1</code>: 集合类型的数据结构<code>MutableSet</code>
</li>
<li>
<code>observers</code>: 数组结构<code>MutableArray</code>
</li>
<li>
<code>timers</code>: 数组结构<code>MutableArray</code>
</li>
</ol>
<p><img src="images/runloopdata02.png" alt="runloopdata02"></p>
<h3>
<a id="21-cfrunloopmode种类" class="anchor" href="#21-cfrunloopmode%E7%A7%8D%E7%B1%BB"></a>2.1 CFRunLoopMode种类</h3>
<ul>
<li>
<strong>kCFRunLoopDefaultMode</strong>: App的默认Mode，通常主线程是在这个Mode下运行</li>
<li>
<strong>UITrackingRunLoopMode</strong>：界面跟踪 Mode，用于 ScrollView 追踪触摸滑动，保证界面滑动时不受其他 Mode 影响</li>
<li>UIInitializationRunLoopMode: 在刚启动 App 时第进入的第一个 Mode，启动完成后就不再使用</li>
<li>GSEventReceiveRunLoopMode: 接受系统事件的内部 Mode，通常用不到</li>
</ul>
<h3>
<a id="22-kcfrunloopcommonmodes-标记" class="anchor" href="#22-kcfrunloopcommonmodes-%E6%A0%87%E8%AE%B0"></a>2.2 kCFRunLoopCommonModes 标记</h3>
<p><strong>kCFRunLoopCommonModes</strong>这玩意, 不是CFRunLoopMode种类, 它只是一种标记.</p>
<h2>
<a id="23-cfrunloopref-的-commonmodes-为什么是存的字符串" class="anchor" href="#23-cfrunloopref-%E7%9A%84-commonmodes-%E4%B8%BA%E4%BB%80%E4%B9%88%E6%98%AF%E5%AD%98%E7%9A%84%E5%AD%97%E7%AC%A6%E4%B8%B2"></a>2.3 CFRunLoopRef 的 commonModes 为什么是存的字符串?</h2>
<p>答: 它代表了CFRunLoopMode这个中数据类型的结构.</p>
<h2>
<a id="24-commonmodes-是种类字符串好比代表了type" class="anchor" href="#24-commonmodes-%E6%98%AF%E7%A7%8D%E7%B1%BB%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%A5%BD%E6%AF%94%E4%BB%A3%E8%A1%A8%E4%BA%86type"></a>2.4 commonModes 是种类,字符串好比代表了type</h2>
<p>可以通过<strong>commonModes</strong>里面的字符串找出一个<strong>Runloop</strong>里面具体的<strong>CFRunLoopMode</strong>对象,像这样.</p>
<p><a href="https://opensource.apple.com/source/CF/CF-635/CFRunLoop.c.auto.html">看苹果CFRunLoop源代码</a></p>
<pre><code>
CFRunLoopModeRef rlm = __CFRunLoopFindMode(rl, modeName, true);

</code></pre>
<h2>
<a id="3-sourcetimerobserver" class="anchor" href="#3-sourcetimerobserver"></a>3. Source/Timer/Observer</h2>
<h3>
<a id="31-source" class="anchor" href="#31-source"></a>3.1 Source</h3>
<p>叫做<code>CFRunLoopSourceRef</code>, 有两种:</p>
<ul>
<li>
<p><code>sources0</code>:需要手动唤醒线程</p>
<ul>
<li>指的是,当我添加一个<code>sources0</code>到<code>Runloop</code>中的时候, 它不会主动唤醒当前线程, 我们需要手动唤醒, 将线程从<strong>内核态</strong>切换到<strong>用户态</strong>
</li>
</ul>
</li>
<li>
<p><code>sources1</code>:<strong>具备唤醒线程的能力</strong></p>
</li>
</ul>
<p><img src="images/runloopdata03.png" alt="runloopdata03"></p>
<h3>
<a id="32-observer" class="anchor" href="#32-observer"></a>3.2 Observer</h3>
<p><strong>CFRunLoopObserverRef</strong></p>
<p>我们可以注册一些<code>Observer</code>, 来实现对<code>Runloop</code>的一些相关时间点的监测观察.
我们可以监测<code>Runloop</code>哪些时间点呢?
主要有六个:</p>
<ol>
<li>
<strong>kCFRunLoopEntry</strong> : <code>runloop</code>准备启动</li>
<li>
<strong>kCFRunLoopBeforeTimers</strong>: 通知观察者,<code>runloop</code>将要对<code>Timer</code>的一些相关事件进行处理了</li>
<li>
<strong>kCFRunLoopBeforeSources</strong>: 将要处理一些<code>Sources</code>事件</li>
<li>
<strong>kCFRunLoopBeforeWaiting</strong>: 通知观察者, <code>runloop</code>将要休眠,<strong>用户态</strong>转<strong>内核态</strong>
</li>
<li>
<strong>kCFRunLoopAfterWaiting</strong>: <strong>内核态</strong>---转---&gt;<strong>用户态</strong>
</li>
<li>
<strong>kCFRunLoopExit</strong>: <code>runloop</code>退出通知</li>
</ol>
<p><img src="images/runloopdata04.png" alt="runloopdata04"></p>
<h3>
<a id="33-cfrunlooptimerref" class="anchor" href="#33-cfrunlooptimerref"></a>3.3 CFRunLoopTimerRef</h3>
<p>它是基于事件的定时器</p>
<p>和我们平时使用的<code>NSTimer</code>是具备**免费调转换(toll-free bridged)**的</p>
<h2>
<a id="4-runloop和mode的关系" class="anchor" href="#4-runloop%E5%92%8Cmode%E7%9A%84%E5%85%B3%E7%B3%BB"></a>4. Runloop和mode的关系</h2>
<p><img src="images/runloopdata05.png" alt="runloopdata05">
<img src="images/runloopdata06.png" alt="runloopdata06"></p>
<h2>
<a id="5-runloopcommonmodes的特殊性" class="anchor" href="#5-runloopcommonmodes%E7%9A%84%E7%89%B9%E6%AE%8A%E6%80%A7"></a>5. RunLoopCommonModes的特殊性</h2>
<p>上面说了, 只能处理一个<code>mode</code>上面的事件, 然后就有问题了, 怎样将同一个<code>Timer</code>同时添加到两个<code>mode</code>上面呢?
答: <strong>RunLoopCommonModes</strong></p>
<p><code>kCFRunLoopCommonModes</code>和<code>NSRunLoopCommonModes</code>一个东西哈.</p>
<ul>
<li>
<code>CommonModes</code>(简称), 不是实际存在的一种<code>Mode</code>
</li>
<li>
<code>CommonModes</code>是同步<code>Source/Timer/Observer</code>到多个<code>mode</code>中的一种技术方案.</li>
</ul></div>
          </div>
        </div>
      </div>
      </div>
  </div>
</body>
</html>